fix(agent-core-v2): resolve reopened agents to their roster branch - #3726
Merged
sailist merged 1 commit intoSep 11, 2026
Merged
Conversation
|
sailist
added a commit
that referenced
this pull request
Sep 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related Issue
Internal bug report (no public issue): reopening an agent after undo + process restart resurrects the undone turns.
Problem
SessionStoresmanages one branch per agent plus a_sessionbranch whoseagent.opened/agent.switched/agent.closedevents fold into a roster mapping each agent to its current branch. This roster must exist because undo is non-destructive:undo('main', 1)forks a new branchmain~2and switches to it, while the oldmainbranch keeps its full pre-undo history.The read side had a gap:
open()resolved branches purely by agent name (tree.has(agentId)→ open the same-named branch) and never consulted the roster. Within the same process this went unnoticed (the in-memory store was already reset), but after a process restartopen('main')opened the stale pre-undo branch and every undone turn came back. The migrate-v2 end-to-end test asserted only the roster contents after a restart, never the history the reopened agent actually sees — exactly the gap.What changed
SessionStores.open()now treats the roster as authoritative: it reads the folded roster first and opens the registered branch when an entry exists (a roster entry pointing at a missing branch fails loudly viaopenBranch— corrupted data, no silent fallback). Without an entry it keeps the existing fallback — open the same-named branch (covers the crash window betweencreateBranchand the persistedagent.opened) or create one fromopts.from— and dispatchesagent.openedto backfill the registration whenever it opens a branch with no roster entry, so first open and crash-window repair share one registration path.main~2, post-undo history) while the fork branch keeps its own full history; the migrate-v2 end-to-end case now also opens the agent after the simulated restart and assertsref.branchand the folded history, not just the roster contents.SessionStoresis only consumed byhuman/tests andpersist/open.tsso far — production DI wiring lands in a follow-up task, so the fix is not user-perceivable yet.Checklist
/approve).gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.